﻿#include "DAFigureContainer.h"
#include <math.h>
#include <QResizeEvent>
#include <QDebug>
#include <QChildEvent>
namespace DA
{
/**
 * @def 定义精度
 */
#define DAFIGURECONTAINER_PRECISION 5

class DAFigureContainerPrivate
{
    DA_IMPL_PUBLIC(DAFigureContainer)
public:
    QMap< QWidget*, QRectF > _widgetPos;
    bool _isResetWidgetPos;
    DAFigureContainerPrivate(DAFigureContainer* p) : q_ptr(p), _isResetWidgetPos(false)
    {
    }
};

DAFigureContainer::DAFigureContainer(QWidget* parent) : QWidget(parent), d_ptr(new DAFigureContainerPrivate(this))
{
}

DAFigureContainer::~DAFigureContainer()
{
    // qDebug() <<"SAFigureContainer destroy";
}

void DAFigureContainer::addWidget(QWidget* widget, const QRectF& posPercent)
{
    if (widget->parentWidget() != this) {
        widget->setParent(this);
    }
    QRect widgetSize;

    calcWidgetSize(posPercent, widgetSize);
    widget->setGeometry(widgetSize);
    // connect(widget,&QObject::destroyed,this,&SAFigureContainer::onWidgetDestroy);
    (d_ptr->_widgetPos)[ widget ] = posPercent;
    widget->installEventFilter(this);
}

void DAFigureContainer::addWidget(QWidget* widget, float xPercent, float yPercent, float wPercent, float hPercent)
{
    addWidget(widget,
              QRectF(setRealPrecision(xPercent, DAFIGURECONTAINER_PRECISION),
                     setRealPrecision(yPercent, DAFIGURECONTAINER_PRECISION),
                     setRealPrecision(wPercent, DAFIGURECONTAINER_PRECISION),
                     setRealPrecision(hPercent, DAFIGURECONTAINER_PRECISION)));
}

QList< QWidget* > DAFigureContainer::getWidgetList() const
{
    QList< QWidget* > res;

    for (auto i = d_ptr->_widgetPos.begin(); i != d_ptr->_widgetPos.end(); ++i) {
        res.append(i.key());
    }
    return (res);
}

QRectF DAFigureContainer::getWidgetPosPercent(QWidget* w) const
{
    return (d_ptr->_widgetPos.value(w));
}

/**
 * @brief 设置窗口的百分比
 * @param w
 * @param posPercent
 */
void DAFigureContainer::setWidgetPosPercent(QWidget* w, const QRectF& posPercent)
{
    auto i = d_ptr->_widgetPos.find(w);

    if (i != d_ptr->_widgetPos.end()) {
        i.value() = posPercent;
    }
}

/**
 * @brief 设置窗口的百分比
 * @param w
 * @param xPercent
 * @param yPercent
 * @param wPercent
 * @param hPercent
 */
void DAFigureContainer::setWidgetPosPercent(QWidget* w, float xPercent, float yPercent, float wPercent, float hPercent)
{
    setWidgetPosPercent(w,
                        QRectF(setRealPrecision(xPercent, DAFIGURECONTAINER_PRECISION),
                               setRealPrecision(yPercent, DAFIGURECONTAINER_PRECISION),
                               setRealPrecision(wPercent, DAFIGURECONTAINER_PRECISION),
                               setRealPrecision(hPercent, DAFIGURECONTAINER_PRECISION)));
}

/**
 * @brief 更新维护的窗口的尺寸
 * @param w 窗口指针
 * @param rect 需要进行设置的尺寸，这个尺寸将是窗口的Geometry，在update过程中，会更新对应的相对位置
 */
void DAFigureContainer::updateWidgetPos(QWidget* w, const QRect& rect)
{
    if (!(d_ptr->_widgetPos.contains(w))) {
        return;
    }
    QRectF present = calcWidgetPosPercent(this, rect);

    (d_ptr->_widgetPos)[ w ] = present;
}

bool DAFigureContainer::isWidgetInContainer(const QWidget* w)
{
    return (d_ptr->_widgetPos.contains(const_cast< QWidget* >(w)));
}

/**
 * @brief 设置允许在窗口改变的时候重新修改widgetPosPersent,此函数需要和 @sa endResetSubWidget 配套
 */
void DAFigureContainer::beginResetSubWidget()
{
    d_ptr->_isResetWidgetPos = true;
}

/**
 * @brief 设置不允许在窗口改变的时候重新修改widgetPosPersent,此函数需要和 @sa beginResetSubWidget 配套
 */
void DAFigureContainer::endResetSubWidget()
{
    d_ptr->_isResetWidgetPos = false;
}

/**
 * @brief 计算size对应SAFigureContainer的位置占比
 * @param c
 * @param size
 * @return 返回rect对应SAFigureContainer的位置占比
 */
QRectF DAFigureContainer::calcWidgetPosPercent(DAFigureContainer* c, const QRect& rect)
{
    QRectF present;
    QSize widgetSize = c->size();

    present.setX(setRealPrecision((qreal)rect.left() / widgetSize.width(), DAFIGURECONTAINER_PRECISION));
    present.setY(setRealPrecision((qreal)rect.top() / widgetSize.height(), DAFIGURECONTAINER_PRECISION));
    present.setWidth(setRealPrecision((qreal)rect.width() / widgetSize.width(), DAFIGURECONTAINER_PRECISION));
    present.setHeight(setRealPrecision((qreal)rect.height() / widgetSize.height(), DAFIGURECONTAINER_PRECISION));
    return (present);
}

/**
 * @brief 通过窗口Percent计算窗口尺寸
 * @param c
 * @param percent
 * @return
 */
QRect DAFigureContainer::calcWidgetRectByPercent(DAFigureContainer* c, const QRectF& percent)
{
    QSize widgetSize = c->size();
    QRect newrect;

    newrect.setRect(widgetSize.width() * percent.left(),
                    widgetSize.height() * percent.top(),
                    widgetSize.width() * percent.width(),
                    widgetSize.height() * percent.height());
    return (newrect);
}

/**
 * @brief 限制浮点数的位数，避免出现过多小数
 * @param v 需要限制的浮点数
 * @param precision 精度，默认为3位
 * @return 限制后的浮点数值
 */
qreal DAFigureContainer::setRealPrecision(qreal v, int precision)
{
    qreal p = pow(10, precision);

    return (round(v * p) / p);
}

void DAFigureContainer::resizeEvent(QResizeEvent* event)
{
    Q_UNUSED(event);
    QRect subWidgetSize;

    for (auto i = (d_ptr->_widgetPos.begin()); i != (d_ptr->_widgetPos.end()); ++i) {
        calcWidgetSize(i.value(), subWidgetSize);
        QWidget* w = i.key();
        //        qDebug()	<<" == " <<w
        //                << "present:"<< i.value()
        //                << " size :" <<  event->size()
        //                << " old:" << event->oldSize()
        //                << " set to :" << subWidgetSize;
        //这里设置尺寸，会导致eventFilter的resizeevent,重新改变了百分比，因此，需要设置忽略百分比改变
        w->setGeometry(subWidgetSize);
    }
    //  QWidget:resizeEvent(event);
}

bool DAFigureContainer::event(QEvent* e)
{
    if (e) {
        if (QEvent::ChildRemoved == e->type()) {
            QChildEvent* ce = static_cast< QChildEvent* >(e);
            QObject* obj    = ce->child();
            if ((nullptr != obj) && obj->isWidgetType()) {
                QWidget* w = (QWidget*)obj;
                d_ptr->_widgetPos.remove(w);
            }
        }
    }
    return (QWidget::event(e));
}

bool DAFigureContainer::eventFilter(QObject* watched, QEvent* event)
{
    if (nullptr == event) {
        return (QWidget::eventFilter(watched, event));
    }
    if (d_ptr->_isResetWidgetPos) {
        if (QEvent::Resize == event->type()) {
            if (watched && watched->isWidgetType()) {
                QWidget* w = qobject_cast< QWidget* >(watched);
                if (w && isWidgetInContainer(w)) {
                    QResizeEvent* e = static_cast< QResizeEvent* >(event);
                    QRectF& data    = (d_ptr->_widgetPos)[ w ];
                    data.setWidth(setRealPrecision(e->size().width() / (double)width(), DAFIGURECONTAINER_PRECISION));
                    data.setHeight(setRealPrecision(e->size().height() / (double)height(), DAFIGURECONTAINER_PRECISION));
                    // qDebug() <<" == " <<watched << " set new:" <<  e->size() << " old" <<e->oldSize() << "present:"<<data;
                }
            }
        } else if (QEvent::Move == event->type()) {
            if (watched && watched->isWidgetType()) {
                QWidget* w = qobject_cast< QWidget* >(watched);
                if (w && isWidgetInContainer(w)) {
                    QMoveEvent* e = static_cast< QMoveEvent* >(event);
                    QRectF& data  = (d_ptr->_widgetPos)[ w ];
                    data.setX(setRealPrecision(e->pos().x() / (double)width(), DAFIGURECONTAINER_PRECISION));
                    data.setY(setRealPrecision(e->pos().y() / (double)height(), DAFIGURECONTAINER_PRECISION));
                }
            }
        }
    }
    return (QWidget::eventFilter(watched, event));
}

void DAFigureContainer::calcWidgetSize(const QRectF& present, QRect& newSize)
{
    newSize = calcWidgetRectByPercent(this, present);
}
}  // End Of Namespace DA
